package controllers

import (
	"errors"
	"github.com/kataras/iris"
	"go_oauth2/constant"
	"go_oauth2/models"
	"go_oauth2/store"
	"time"
)

type CheckTokenRequestJson struct {
	AccessToken string `json:"access_token" validate:"required"`
	GrantType   string `json:"grant_type" validate:"required"`
}

func Check(context iris.Context) {

	// 校验客户端配置信息是否符合标准
	isChecked, _ := CheckRequestClient(context)
	if !isChecked {
		return
	}

	// 格式化输入信息
	checkTokenRequestJson := new(CheckTokenRequestJson)
	if err := context.ReadJSON(&checkTokenRequestJson); err != nil {
		// 错误的请求
		context.StatusCode(iris.StatusBadRequest)
		// 请求参数错误，不能格式化成结构体
		_, _ = context.JSON(ApiResourceError(constant.RequestBodyError))
		return
	}

	// 校验结构体参数是否符合规则
	if err := validate.Struct(checkTokenRequestJson); err != nil {
		// 错误的请求
		context.StatusCode(iris.StatusBadRequest)
		// 参数不符合规范
		_, _ = context.JSON(ApiResourceError(validatorErrorData(err)))
		return
	}

	accessToken := checkTokenRequestJson.AccessToken
	// 判断grant_type是否符合规则
	if checkTokenRequestJson.GrantType != constant.CheckToken && len(accessToken) == 0 {
		// 错误的请求
		context.StatusCode(iris.StatusBadRequest)
		// 参数不符合规范
		_, _ = context.JSON(ApiResourceError(constant.RequestBodyError))
		return
	}

	session := store.GetStore()
	tokenInfo, isExist, err := session.Find(accessToken)
	if !isExist || err != nil {
		// 授权错误。当出现StatusUnauthorized时都应该重新登录
		context.StatusCode(iris.StatusUnauthorized)
		// 账号没有授权信息，无法刷新token
		_, _ = context.JSON(ApiResourceError(constant.UserAuthorizationError))
		return
	}

	authToken := models.Bytes2OAuth(tokenInfo)

	// 校验access_token是否过期
	expirationTimeString := authToken.Expiration
	expirationTime, _ := time.Parse(constant.TimeFormat, expirationTimeString)
	if time.Now().After(expirationTime) {
		// 授权错误。当出现StatusUnauthorized时都应该重新登录
		context.StatusCode(iris.StatusUnauthorized)
		// access_token已经过期，需要重新登录
		_, _ = context.JSON(ApiResourceError(constant.AccessTokenTimeoutError))
		return
	}

	// 授权校验通过
	newTimeout, err := refreshTimeout(authToken, session)
	if err != nil {
		// 程序内部错误
		context.StatusCode(iris.StatusInternalServerError)
		// 程序内部意外的错误
		_, _ = context.JSON(ApiResourceError(constant.ProgramError))
		return
	}
	context.StatusCode(iris.StatusOK)
	_, _ = context.JSON(ApiResourceSuccess(newTimeout))
	return
}

func refreshTimeout(authToken *models.OAuthToken, session store.Store) (string string, err error) {
	// 刷新access_token的过期时间
	expTime := time.Now().Unix() + constant.TokenDefaultTimeout
	t := time.Unix(expTime, 0)
	date := t.Format(constant.TimeFormat)
	authToken.Expiration = date

	// 更新授权信息
	if err := session.Save(authToken.Token, models.OAuth2Bytes(authToken)); err != nil {
		return "", errors.New("程序内部错误")
	}
	return date, nil
}
